/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.freedom.imarket.controller;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.freedom.imarket.controller.json.designer.FormDesigner;
import org.freedom.imarket.controller.json.properties.Field;
import org.freedom.imarket.dao.AbstractEntityDAO;
import org.freedom.imarket.util.converter.TableColumnNameConverter;
import org.freedom.util.HibernateUtils;
import org.freedom.util.VelocityUtil;
import org.hibernate.MappingException;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Property;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ReflectionUtils;

/**
 *
 * @author edoardo
 */
public abstract class AbstractEntityController<T> implements InitializingBean {

    @Autowired
    private Properties velocityProperties;
    @Autowired
    private TableColumnNameConverter columnNameConverter;
    @Autowired
    private TableColumnNameConverter columnNameToHeaderConverter;
    private Column[] columns;
    private JSONArray fields;
    private Property[] properties;
    private Map<String, Field> propertiesFieldsRelation = new HashMap<String, Field>();

    public abstract AbstractEntityDAO<T> getDAO();

    public abstract Class getEntityClass();

    public abstract String getJsListClass();

    public abstract String getListWidgetAlias();

    public abstract String getListTitle();

    public abstract String getStoreName();

    public abstract String getJsModelClassName();

    public abstract String getJsStoreClassName();

    public abstract String getJsEditAlias();

    public abstract String getJsEditClassName();

    public abstract String getJsEditTitle();

    public final AbstractEntityController init() throws MappingException {
        if (columns == null) {
            columns = HibernateUtils.getEntityColumns(getEntityClass());
            properties = HibernateUtils.getEntityProperties(getEntityClass());
            SingleTableEntityPersister ep = HibernateUtils.getEntityMetaData(getEntityClass().getName());

            System.out.println("Columns.length: " + columns.length);
            System.out.println("Proprties.length: " + properties.length);
            fields = new JSONArray();
            for (int i = 0; i < properties.length; i++) {
                Property property = properties[i];
                if (!isComponent(property)) {
                    Field aField = createJsonField(property);
                    propertiesFieldsRelation.put(property.getName(), aField);
                    fields.put(aField.toJsonObject());

                    System.out.println(properties[i].getType().getName());
                }
            }
        }
        return this;

    }

    public final String loadListJs(HttpServletRequest request, HttpServletResponse response) throws JSONException, IOException {
        response.setContentType("text/javascript");
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("class", getJsListClass());
        params.put("alias", getListWidgetAlias());
        params.put("title", getListTitle());
        JSONArray columns = new JSONArray();
        Property[] properties = HibernateUtils.getEntityProperties(getEntityClass());
        for (int i = 0; i < properties.length; i++) {
            Property property = properties[i];
            JSONObject column = new JSONObject();
//            if(!isPartOfCompositeId(property)){

            column.put("dataIndex", property.getName());
            column.put("header", getColumnNameToHeaderConverter().translate(HibernateUtils.getColumnByProperty(property).getName()));

//            }else{
//                
//                
//            }

            columns.put(column);
        }
        params.put("columns", columns.toString());
        params.put("store", getStoreName());
        VelocityUtil velocityUtil = VelocityUtil.getInstance(getVelocityProperties());
        velocityUtil.doMerge(response.getWriter(), params, "org/freedom/imarket/controller/js/template/list.template");

        return null;
    }

    public final String loadGrid(HttpServletRequest request, HttpServletResponse response) throws IOException, JSONException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        response.setContentType("text/javascript");

        //caricamento del model template con velocity

        List societas = getDAO().loadAll();


        VelocityUtil velocityUtil = VelocityUtil.getInstance(getVelocityProperties());

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("model", getJsModelClassName());
        params.put("class", getJsStoreClassName());



        JSONArray jsonData = new JSONArray();
//        List<String> innerProperties = new ArrayList<String>();//contiene tutte le properties che fanno parte della chiave primaria.
        for (int i = 0; i < societas.size(); i++) {
            Object societa = societas.get(i);
            JSONObject row = new JSONObject();
            for (int j = 0; j < getProperties().length; j++) {
                Property property = getProperties()[j];
                String methodName = getMethodName(property);
                Method method = ReflectionUtils.findMethod(getEntityClass(), methodName);
                if (!isPartOfCompositeId(property)) {
                    row.put(property.getName(), method.invoke(societa, null));
                } else {
                    Class component = HibernateUtils.getComponentClassByProperty(getEntityClass(), property);
                    Property innerProperty = HibernateUtils.findIdentifierPropertyByProperty(getEntityClass(), property);
                    Object obj = ReflectionUtils.findMethod(getEntityClass(), getMethodName(innerProperty)).invoke(societa, null);//ottengo l'ggetto con le chiavi primarie
                    Method innerMethod = ReflectionUtils.findMethod(component, getMethodName(property));
                    row.put(property.getName(), innerMethod.invoke(obj, null));

                }

            }
            jsonData.put(row);
        }
        System.out.println(jsonData.toString());

        params.put("jsonData", jsonData.toString());

        velocityUtil.doMerge(response.getWriter(), params, "org/freedom/imarket/controller/js/template/store.template");

        return null;

    }

    public String loadEdit(HttpServletRequest request, HttpServletResponse response) throws IOException, JSONException {

        response.setContentType("text/javascript");
        VelocityUtil velocityUtil = VelocityUtil.getInstance(getVelocityProperties());
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("class", getJsEditClassName());
        params.put("alias", getJsEditAlias());
        params.put("title", getJsEditTitle());
        
        
        JSONArray formItems = FormDesigner.create(this.getEntityClass());
        
        params.put("formItems", formItems);
        
       String formButtons = FormDesigner.designButtons(this.getEntityClass());
        params.put("formButtons", formButtons);


        velocityUtil.doMerge(response.getWriter(), params, "org/freedom/imarket/controller/js/template/edit.template");
        //caricamento del model template con velocity
        return null;


    }

    public final String loadModel(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("----------> loadModel");
        response.setContentType("text/javascript");


//        System.out.println("fields: " + fields.toString());
//        System.out.println("velocity-properties: " + velocityProperties);
        VelocityUtil velocityUtil = VelocityUtil.getInstance(getVelocityProperties());
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("class", getJsModelClassName());
        params.put("fields", getFields().toString());
        velocityUtil.doMerge(response.getWriter(), params, "org/freedom/imarket/controller/js/template/model.template");
        //caricamento del model template con velocity
        return null;

    }
    public final String loadController(HttpServletRequest request, HttpServletResponse response) {
        return null;
    }

    /**
     * @return the velocityProperties
     */
    protected Properties getVelocityProperties() {
        return velocityProperties;
    }

    /**
     * @return the columnNameConverter
     */
    protected TableColumnNameConverter getColumnNameConverter() {
        return columnNameConverter;
    }

    /**
     * @return the columnNameToHeaderConverter
     */
    protected TableColumnNameConverter getColumnNameToHeaderConverter() {
        return columnNameToHeaderConverter;
    }

    /**
     * @return the columns
     */
    protected Column[] getColumns() {
        return columns;
    }

    /**
     * @return the fields
     */
    protected JSONArray getFields() {
        return fields;
    }

    /**
     * @return the properties
     */
    protected Property[] getProperties() {
        return properties;
    }

    /**
     * @return the propertiesFieldsRelation
     */
    protected Map<String, Field> getPropertiesFieldsRelation() {
        return propertiesFieldsRelation;
    }

    private Field createJsonField(Property property) throws MappingException {
        Field aField = new Field();
        aField.setName(property.getName());
        aField.setType(property.getType().getName());
        return aField;
    }

    private boolean isComponent(Property property) throws MappingException {
        return property.getType().getName().startsWith("component");
    }

    private String getMethodName(Property property) {
        return new StringBuilder("get").append(StringUtils.capitalize(property.getName())).toString();
    }

    private boolean isPartOfCompositeId(Property property) {
        for (int i = 0; i < properties.length; i++) {
            Property tmpProperty = properties[i];
            if (tmpProperty.isComposite()) {
                if (tmpProperty.getType().getName().indexOf(property.getName()) != -1) {
                    return true;
                }
            }

        }
        return false;
    }

	public void afterPropertiesSet() throws Exception {
        init();
    }

	public void initComponent(HttpServletRequest request, HttpServletResponse response) {
		// TODO Auto-generated method stub
		
	}

  

}
